package xyz.mumuwei.youthcourseserver.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import xyz.mumuwei.youthcourseserver.common.dto.PageDto;
import xyz.mumuwei.youthcourseserver.common.dto.TemplateData;
import xyz.mumuwei.youthcourseserver.common.dto.WechatMessageDto;
import xyz.mumuwei.youthcourseserver.common.lang.Const;
import xyz.mumuwei.youthcourseserver.common.lang.Result;
import xyz.mumuwei.youthcourseserver.job.OrderStateRefreshJob;
import xyz.mumuwei.youthcourseserver.mapper.CourseMapper;
import xyz.mumuwei.youthcourseserver.mapper.OrderMapper;
import xyz.mumuwei.youthcourseserver.mapper.UserInfoMapper;
import xyz.mumuwei.youthcourseserver.mapper.UserMapper;
import xyz.mumuwei.youthcourseserver.pojo.Course;
import xyz.mumuwei.youthcourseserver.pojo.Order;
import xyz.mumuwei.youthcourseserver.pojo.UserInfo;
import xyz.mumuwei.youthcourseserver.service.OrderService;
import xyz.mumuwei.youthcourseserver.service.WechatService;
import xyz.mumuwei.youthcourseserver.utils.*;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.UUID;

/**
 * @author mumuwei
 * @since 2022-02-19
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    final UserMapper userMapper;
    final OrderMapper orderMapper;
    final UserInfoMapper infoMapper;
    final CourseMapper courseMapper;
    final RedisUtil redisUtil;
    final WechatService wechatService;

    /**
     * 分页获取订单列表
     *
     * @param pageDto 分页参数
     * @return 查询结果
     */
    @Override
    public Result getOrderPage(PageDto pageDto) {
        return Result.success(orderMapper.getOrderByPage(
                new Page<>(pageDto.getCurrent(), pageDto.getSize()),
                pageDto.getKey())
        );
    }

    /**
     * 获取订单列表
     *
     * @return 订单列表
     */
    @Override
    public Result getOrderList() {
        return Result.success(orderMapper.getOrderList());
    }

    /**
     * 创建订单
     *
     * @param order 订单信息
     * @return 跳转支付宝 html
     */
    @Override
    public Result createOrder(Order order) throws AlipayApiException, SchedulerException {
        Course course = courseMapper.selectById(order.getCourseId());
        if (course.getSurplus() <= 0) {
            return Result.fail("课程已售空！");
        }
        order.setTotalPrice(course.getPrice());
        order.setCourseName(course.getName());
        UserInfo userInfo = infoMapper.selectOne(
                new QueryWrapper<UserInfo>()
                        .eq("phone", order.getPhone())
        );
        // 判断新老学员
        if (userInfo == null) {
            // 新学员
            UserInfo info = new UserInfo();
            info.setRealName(order.getStudentName());
            info.setPhone(order.getPhone());
            info.setRoleId(Const.STUDENT_ROLE_CODE);
            int insert = infoMapper.insert(info);
            if (insert <= 0) {
                log.error("创建订单，存储学员信息失败！");
                return Result.fail("服务器内部错误！");
            }
            order.setStudentId(info.getId());
        } else {
            // 判断手机号与学员姓名是否匹配，不匹配则告知手机已绑定
            if (!userInfo.getRealName().equals(order.getStudentName())) {
                return Result.fail("手机号码已绑定,请检查学员姓名是否有无！");
            }
            // 老学员
            order.setStudentId(userInfo.getId());
        }

        Order one = orderMapper.selectOne(
                new QueryWrapper<Order>()
                        .eq("course_id", order.getCourseId())
                        .eq("student_id", order.getStudentId())
                        .eq("state", 1)
        );
        if (one == null) {
            // 首次创建
            return createCommon(order, true, true);
        } else {
            // 已经存在待支付订单
            one.setPayType(order.getPayType());
            return createCommon(one, true, false);
        }


    }

    /**
     * 更新学员信息
     *
     * @param info 学员信息
     * @return 更新结果
     */
    @Override
    public Result updateStudent(UserInfo info) {
        int i = infoMapper.updateById(info);
        if (i > 0) {
            return Result.success("更新学员信息成功！");
        }
        return Result.fail("更新学员信息失败！");
    }

    /**
     * 根据订单编号删除订单
     *
     * @param code 订单编号
     * @return 删除结果
     */
    @Override
    public Result deleteByOrderId(String code) {
        int code1 = orderMapper.delete(new QueryWrapper<Order>().eq("code", code));
        if (code1 > 0) {
            return Result.success("删除订单成功！");
        }
        return Result.fail("删除订单失败！");
    }

    /**
     * 根据订单编号，请求支付宝，查询订单状态
     *
     * @param code 订单编号
     */
    @Override
    public void queryOrderInAlipayByCode(String code) throws AlipayApiException {
        // 订单编号不为空
        if (!"".equals(code)) {
            Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("code", code));
            if (order.getState() == 1) {
                // 待支付,查询支付状态
                AlipayTradeQueryResponse response = AlipayUtil.queryOrderStatus(code);
                if (Const.ALIPAY_SUCESS.equals(response.getTradeStatus())) {
                    // 支付成功，判断是否有课程余量，修改支付状态
                    Course course = courseMapper.selectById(order.getCourseId());
                    if (course.getSurplus() > 0) {
                        // 课程有余量
                        order.setState(0);
                        // 设置支付时间
                        order.setPayTime(String.valueOf(response.getSendPayDate().getTime()).substring(0, 10));
                        // 设置支付宝订单号
                        order.setPayId(response.getTradeNo());
                    } else {
                        // 课程无余量 退款
                        order.setState(2);
                    }
                    orderMapper.updateById(order);
                }
            }
        }
    }

    /**
     * 处理支付宝异步通知请求
     *
     * @param request 请求对象
     */
    @Override
    public void alipayNotifyHandle(HttpServletRequest request) throws AlipayApiException, ParseException {
        // 支付宝通知验签
        if (AlipayUtil.signVerified(request)) {
            // 校验通过   获取订单状态
            String status = request.getParameter("trade_status");
            if (Const.ALIPAY_SUCESS.equals(status)) {
                // 支付成功  获取订单信息
                // 1.订单编号
                String code = request.getParameter("out_trade_no");
                // 更新订单状态
                Order order = new Order();
                order.setCode(code);
                // 判断是否有课程余量
                Order oldOrder = orderMapper.selectOne(
                        new QueryWrapper<Order>()
                                .eq("code", code)
                );
                Course course = courseMapper.selectById(oldOrder.getCourseId());
                if (course.getSurplus() > 0) {
                    // 课程有余量，修改课程剩余量
                    course.setSurplus(course.getSurplus() - 1);
                    courseMapper.updateById(course);
                    order.setState(0);
                    // 2.支付宝订单号
                    String alipayId = request.getParameter("trade_no");
                    // 3.付款时间
                    // gmt_payment=2022-03-18 10:28:48
                    String gmtPayment = String.valueOf(
                            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                                    .parse(request.getParameter("gmt_payment"))
                                    .getTime()
                    ).substring(0, 10);
                    order.setPayId(alipayId);
                    order.setPayTime(gmtPayment);

                    // 发送微信消息到用户
                    oldOrder.setPayTime(gmtPayment);
                    Integer userId = infoMapper.selectById(oldOrder.getStudentId()).getUserId();
                    String openId = userMapper.selectById(userId).getOpenId();
                    if(openId != null && !"".equals(openId)){
                        sendWechatMessage(oldOrder, openId);
                    }
                } else {
                    // 课程报满，没有余量
                    // 订单退款
                    order.setState(2);
                }
                orderMapper.update(order, new QueryWrapper<Order>().eq("code", code));
            }
        }
    }

    /**
     * 根据订单编号获取订单信息
     *
     * @param code 订单编号
     * @return 查询的订单信息
     */
    @Override
    public Result getOrderByCode(String code) {
        Order order = orderMapper.getOrderByCode(code);
        if (order == null) {
            return Result.fail("订单号关联订单不存在！");
        }
        return Result.success(order);
    }

    /**
     * 学生前台购买课程
     *
     * @param order 订单信息
     * @param uid   用户id
     * @param isWeb 是否Pc端支付， false则为移动端支付
     * @return 支付宝跳转表单
     */
    @Override
    public Result createByStudent(Order order, Integer uid, Boolean isWeb) throws AlipayApiException, SchedulerException {
        UserInfo student = infoMapper.selectOne(
                new QueryWrapper<UserInfo>()
                        .eq("user_id", uid)
        );
        if (student == null) {
            return Result.fail("参数有误！未绑定学员姓名，手机号");
        }

        // 校验是否已经存在订单
        Order one = orderMapper.selectOne(
                new QueryWrapper<Order>()
                        .eq("course_id", order.getCourseId())
                        .eq("student_id", student.getId())
                        .eq("state", 1)
        );
        if (one != null) {
            // 订单存在，继续支付
            one.setPayType(order.getPayType());
            one.setCourseName(courseMapper.selectById(order.getCourseId()).getName());
            return createCommon(one, isWeb, false);
        } else {
            // 订单不存在，创建订单
            order.setStudentId(student.getId());
            Course course = courseMapper.selectById(order.getCourseId());
            if (course.getSurplus() <= 0) {
                return Result.fail("课程已售空！");
            }
            order.setTotalPrice(course.getPrice());
            order.setCourseName(course.getName());
            return createCommon(order, isWeb, true);
        }
    }

    /**
     * 分页 根据学生id获取订单列表
     *
     * @param pageDto 分页参数
     * @return 订单列表
     */
    @Override
    public Result getByStudentId(PageDto pageDto) {
        return Result.success(orderMapper.getOrderPageByStudent(
                new Page<>(pageDto.getCurrent(), pageDto.getSize()),
                pageDto.getId())
        );
    }

    /**
     * 根据用户id和订单编号校验信息，并创建支付宝订单
     *
     * @param orderId 订单编号
     * @param model   视图
     */
    @Override
    public void createWapAlipay(String orderId, Model model) {
        String code = redisUtil.get(Const.USER_PAY_ORDER_REDIS + orderId).toString();
        if (!"".equals(code)) {
            // 订单存在，用户正确,创建支付宝支付
            Order one = orderMapper.selectOne(new QueryWrapper<Order>().eq("code", code));
            if (one.getState() == 0) {
                // 已经支付
                model.addAttribute("isPay", true);
                model.addAttribute("message", "该订单已被支付，请回到小程序中查看！");
            } else {
                model.addAttribute("isPay", false);
                model.addAttribute("message", "请核对一下信息是否正确，若无问题，请进行支付。");
                one.setCourseName(courseMapper.selectById(one.getCourseId()).getName());
                UserInfo student = infoMapper.selectById(one.getStudentId());
                model.addAttribute("realName", TextUtil.vaildRalName(student.getRealName()));
                model.addAttribute("courseName", one.getCourseName());
                model.addAttribute("phone", TextUtil.vaildPhone(student.getPhone()));
            }
        } else {
            // 订单不存或用户不正确
            model.addAttribute("message", "订单与用户信息匹配错误或订单不存在，请检查请求地址是否有误！");
        }
    }

    /**
     * 创建移动端支付宝支付
     *
     * @param orderId redis缓存id
     * @return 支付宝支付订单
     */
    @Override
    public Result gotoWapAlipay(String orderId) throws AlipayApiException {
        String code = redisUtil.get(Const.USER_PAY_ORDER_REDIS + orderId).toString();
        Order one = orderMapper.selectOne(new QueryWrapper<Order>().eq("code", code));
        one.setCourseName(courseMapper.selectById(one.getCourseId()).getName());
        AlipayTradeWapPayResponse response = AlipayUtil.createWapAlipay(one);
        if (response.isSuccess()) {
            redisUtil.delete(Const.USER_PAY_ORDER_REDIS + orderId);
            return Result.success("订单创建成功", response.getBody());
        } else {
            return Result.fail(response.getMsg());
        }
    }

    /**
     * 根据订单编号去取消订单信息
     *
     * @param code 订单编号
     * @return 操作结果
     */
    @Override
    public Result cancelOrderByCode(String code) throws SchedulerException {
        Order one = orderMapper.selectOne(new QueryWrapper<Order>().eq("code", code));
        one.setState(Const.ORDER_STATE_CANCLE);
        int updateById = orderMapper.updateById(one);
        if (updateById > 0) {
            // 取消订单检测
            QuartzUtil.getInstance().deleteJob(one.getId().toString(), "orderStateRefresh");
            return Result.success();
        }
        return Result.fail("取消订单失败,请重试!");
    }

    /**
     * 公共生成订单步骤
     *
     * @param order     订单信息
     * @param isWeb     是否网页端支付请求，false则为移动端支付请求
     * @param isCreated 是否是首次创建订单， ture 首次创建 false 已创建未支付
     * @return 支付宝表单
     * @throws AlipayApiException 支付宝请求异常
     */
    private Result createCommon(Order order, Boolean isWeb, Boolean isCreated) throws AlipayApiException, SchedulerException {
        // 判断支付方式,若现金支付,则状态 0 ,否则状态 1
        if (Const.PAY_CASH_CODE.equals(order.getPayType())) {
            order.setState(0);
            order.setPayTime(TimeUtil.getCurrentTimestamp());
        } else {
            order.setState(1);
        }

        if (isCreated) {
            // 生成订单号
            order.setCode("YMS" + UUID.randomUUID().toString().replaceAll("-", ""));
            int insert1 = orderMapper.insert(order);
            if (insert1 <= 0) {
                log.error("创建订单信息失败！");
                return Result.fail("服务器内部错误！");
            }


            HashMap<String, Object> map = new HashMap<>(2);
            map.put("orderId", order.getId());

            // 创建订单状态维护任务
            QuartzUtil.getInstance().addJob(OrderStateRefreshJob.class,
                    order.getId().toString(),
                    "orderStateRefresh",
                    TimeUtil.getCronExpress(Const.ORDER_REFRESH_DELAY),
                    map);

        } else {
            if (order.getPayType().equals(Const.PAY_CASH_CODE)) {
                orderMapper.updateById(order);
            }
        }


        // 判断是否移动端支付，是则返回订单编号，引导用户浏览器访问
        if (!isWeb) {
            // 存redis
            String orderId = GenerateCodeUtil.randomOrderId();
            redisUtil.set(Const.USER_PAY_ORDER_REDIS + orderId, order.getCode(), 1000 * 60 * 60 * 24);
            return Result.success("订单创建成功，请支付！", orderId);
        }

        return createPay(order);
    }

    /**
     * 判断支付类型，调用对应支付SDK
     *
     * @param order 订单信息
     */
    private Result createPay(Order order) throws AlipayApiException {
        // 创建订单成功,判断支付类型 0 默认现金支付
        if (Const.PAY_CASH_CODE.equals(order.getPayType())) {
            return Result.success("创建订单成功", order.getCode());
        } else if (Const.PAY_ALIPAY_CODE.equals(order.getPayType())) {
            // PC端支付请求 支付宝支付,调用工具类
            AlipayTradePagePayResponse response = AlipayUtil.createAliPay(order);
            if (response.isSuccess()) {
                return Result.success("创建订单成功!", response.getBody());
            } else {
                return Result.fail(response.getMsg());
            }
        } else if (Const.PAY_WECHAT_CODE.equals(order.getPayType())) {
            // 微信其他支付
            log.info("其他支付");
        }
        return Result.fail("请求支付失败，服务器内部错误！");
    }

    private void sendWechatMessage(Order order, String openId) {
        HashMap<String, TemplateData> data = new HashMap<>(6);
        data.put("character_string1", new TemplateData(order.getCode()));
        data.put("thing2", new TemplateData(courseMapper.selectById(order.getCourseId()).getName()));
        data.put("amount3", new TemplateData("￥" + order.getTotalPrice()));
        data.put("date4", new TemplateData(TimeUtil.dateFormat(order.getPayTime(), "yyyy年MM月dd日 kk:mm:dd")));
        data.put("thing5", new TemplateData("请根据课表按时预约参加课程"));

        WechatMessageDto wechatMessageDto = new WechatMessageDto();
        wechatMessageDto.setTouser(openId);
        wechatMessageDto.setTemplate_id(Const.PAY_WECHAT_TEMPLATE_ID);
        wechatMessageDto.setData(data);
        log.info(wechatService.subscribeMessageSend(wechatMessageDto).toString());
    }

}
